package com.spzx.cart.service.impl;


import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.SpzxService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.SkuPrice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author ChenXing
 * @Description 购物车业务层，存在 redis 里面，同时要考虑数量问题
 * @Create 2024/8/13 11:43
 */

@Service
public class CartServiceImpl implements ICartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SpzxService spzxService;


    @Override
    public void addToCart(Long skuId, Integer skuNum) {

        // 获取当前登录用户的id
        //Long userId = SecurityContextHolder.getUserId();
        Long userId = SecurityUtils.getUserId();

        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);

        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);

        //3.判断是添加还是更新 cache (缓存)
        // 从缓存中尝试拿出来，拿不出来就是添加
        CartInfo cartInfoCache = hashOps.get(skuId+"");

        if(cartInfoCache!=null){
        // 数量加1
            cartInfoCache.setSkuNum(cartInfoCache.getSkuNum()+skuNum);
        }else {

            // 通过skuId，查询product商品sku信息
            ProductSku productSku = spzxService.getProductSku(skuId, SecurityConstants.INNER).getData();
            // 封装
            cartInfoCache=new CartInfo();
            cartInfoCache.setSkuId(skuId);
            cartInfoCache.setSkuNum(skuNum);
            cartInfoCache.setSkuName(productSku.getSkuName());
            cartInfoCache.setThumbImg(productSku.getThumbImg());
            cartInfoCache.setIsChecked(1);
            cartInfoCache.setUserId(userId);
            // 查询实时价格，因为productSku是缓存数据
            SkuPrice price = spzxService.getSkuPrice(skuId, SecurityConstants.INNER).getData();
            cartInfoCache.setCartPrice(price.getSalePrice());
            cartInfoCache.setSkuPrice(price.getSalePrice());
        }
        // 存入redis
        hashOps.put(skuId+"",cartInfoCache);
    }

    @Override
    public List<CartInfo> getCartList() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);
        // 从 redis 把数据查出来
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        // 这里是否需要判空保护？ 自己加的代码，有待斟酌
        Assert.notEmpty(cartInfoList,"购物车不能为空");

        // 查出来之后还要 更改实时价格

        // 方法一: 代码思路简单，但是有n次远程调用，效率太低,如果只有一次远程调用的话，效率会高很多
//        for (CartInfo cartInfo:cartInfoList) {
//            // 查每一个的实时价格
//            SkuPrice skuPrice = spzxService.getSkuPrice(cartInfo.getSkuId(), SecurityConstants.INNER).getData();
//            cartInfo.setCartPrice(skuPrice.getSalePrice());
//            cartInfo.setSkuPrice(skuPrice.getSalePrice());
//        }

        // 方法二: 先将所有的 skuId 集合起来，通过这集合再将所有的  skuPrice 集合起来，最后再进行匹配
        List<Long> skuIds   = cartInfoList.stream().map(cartInfo -> {return cartInfo.getSkuId();}).collect(Collectors.toList());
        // 通过 skuIds 集合 获取 skuPrice 通过一次远程调用去查
        List<SkuPrice> skuPriceList = spzxService.getSkuPriceList(skuIds,SecurityConstants.INNER).getData();

        // 双层循环进行赋值，但代码有点不好看

//        for (CartInfo cartInfo:cartInfoList) {
//            for (SkuPrice skuPrice:skuPriceList) {
//                if(cartInfo.getSkuId().longValue()==skuPrice.getSkuId().longValue()){
//                    cartInfo.setCartPrice(skuPrice.getSalePrice());
//                    cartInfo.setSkuPrice(skuPrice.getSalePrice());
//                }
//            }
//        }

        Map<Long, SkuPrice> skuPriceMap =  skuPriceList.stream().collect(Collectors.toMap(skuPrice -> skuPrice.getSkuId(), skuPrice -> skuPrice));
        // 封装实时价格信息
        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setCartPrice(skuPriceMap.get(cartInfo.getSkuId()).getSalePrice());
            cartInfo.setSkuPrice(skuPriceMap.get(cartInfo.getSkuId()).getMarketPrice());
        }

        return cartInfoList;
    }

    @Override
    public void deleteCart(Long skuId) {

        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        hashOperations.delete(skuId.toString());

    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {

        Long userId = SecurityContextHolder.getUserId();
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);


        // 先获取用户选择的商品
        if (hashOperations.hasKey(skuId.toString())) {
            CartInfo cartInfoUpd = hashOperations.get(skuId.toString());
            // cartInfoUpd 写会缓存
            cartInfoUpd.setIsChecked(isChecked);
            // 更新缓存
            hashOperations.put(skuId.toString(), cartInfoUpd);
        }
    }

    @Override
    public void allCheckCart(Integer isChecked) {
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);


        List<CartInfo> cartInfoList = hashOperations.values();

        // 这也是一个流操作
        cartInfoList.forEach(item -> {
            CartInfo cartInfoUpd = hashOperations.get(item.getSkuId().toString());
            cartInfoUpd.setIsChecked(isChecked);

            // 更新缓存
            hashOperations.put(item.getSkuId().toString(), cartInfoUpd);
        });
    }

    @Override
    public void clearCart() {

        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        // 被选中的购物车集合
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 所有购物车集合
        List<CartInfo> cartInfoList = hashOperations.values();
        // 过滤掉未选中的
        List<CartInfo> cartInfos = cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).collect(Collectors.toList());
        return cartInfos;
    }

    @Override
    public Boolean deleteCartCheckedList(Long userId) {
        List<CartInfo> cartCheckedList = getCartCheckedList(userId);
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        for (CartInfo cartInfo:cartCheckedList) {
            hashOperations.delete(cartInfo.getSkuId().toString());
        }
        return true;
    }

    @Override
    public void updateCartPrice(Long userId) {
        System.out.println("根据userId查询购物车信息，然后用ids查询实时价格信息，然后重新赋值购物车价格存入redis");
        List<CartInfo> cartCheckedList = getCartCheckedList(userId);
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        for (CartInfo cartInfo:cartCheckedList) {
            Long skuId = cartInfo.getSkuId();
            SkuPrice skuPrice = spzxService.getSkuPrice(skuId, SecurityConstants.INNER).getData();
            cartInfo.setSkuPrice(skuPrice.getSalePrice());
            cartInfo.setCartPrice(skuPrice.getSalePrice());
            hashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
        }
    }

    private String getCartKey(Long userId) {
        //定义key user:userId:cart
        return "user:cart:" + userId;
    }
}
